package abstractGA;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import foundation.fileUtil.DataCell;
import foundation.fileUtil.PropFileUtil;

/**
 * GA参数类
 */
public class GAParameter {

	// 配置文件工具类
	protected PropFileUtil propFileUtil = null;
	// 染色体的长度
	protected int chromLen;
	// 交叉概率
	protected float crossProb = 0;
	// 变异概率
	protected float mutateProb = 0;
	// 最大迭代次数
	protected int maxIterNum = 0;
	// 停机条件（不发生变化代数）
	protected int noChgGenNum = 0;
	// 种群规模
	protected int popuSize = 0;
	// 可用于染色体位编码的字符串
	protected List<String> bitCodeStrs = new ArrayList<String>();
	// 保存<位编码字符，最多使用次数>的哈希表
	protected Hashtable<String, Integer> bitCodeHtb = new Hashtable<String, Integer>();
	// 是否需要输出每代种群中各个体信息到Excel
	protected boolean needOutPopulation = false;
	// 是否需要输出GA的参数设置到Excel
	protected boolean neeOutPara = false;
	// 是否需要使用代理模型
	protected boolean needSurModel = false;
	// 采样的样本数，真值样本采集够后启动机器学习
	protected int sampleNum = 400;
	// 预测次数，超过该次数需要求解真值
	protected int predictNum = 14 * 30 * 20;

	public GAParameter() {

	}

	public GAParameter(String gaCfgFileName) {
		propFileUtil = PropFileUtil.getInstance(gaCfgFileName);
	}

	// 获取位编码字符串
	public List<String> getBitCodeStrs() {
		if (bitCodeStrs.size() == 0) {
			Hashtable<String, Integer> tempHtb = getBitCodeHtb();
			Set<String> bitCodeSet = tempHtb.keySet();
			for (String bitCodeStr : bitCodeSet) {
				bitCodeStrs.add(bitCodeStr);
			}
		}
		return bitCodeStrs;
	}

	/**
	 * 从算法的配置文件中获取<位编码字符，最多使用次数>的哈希表 @return：<位编码字符，最多使用次数>的哈希表
	 */
	public Hashtable<String, Integer> getBitCodeHtb() {
		if (bitCodeHtb.size() == 0) {
			// 获取配置字符串
			String bitCodeStrs = propFileUtil.getParameterValue("bitCodeStrs");
			// 去括号和逗号处理
			String[] tempBitcodes = bitCodeStrs.trim().split(",");
			for (int i = 0; i < tempBitcodes.length; i++) {
				String tempBitcode = tempBitcodes[i].replace('(', ' ').trim();
				tempBitcode = tempBitcode.replace(')', ' ').trim();
				tempBitcodes[i] = tempBitcode;
			}
			// 构造编码字符和使用次数哈希表
			for (int j = 0; j < tempBitcodes.length; j = j + 2) {
				String bitCodeSb = tempBitcodes[j];
				int bitCodeUsedNum = Integer.parseInt(tempBitcodes[j + 1]);
				bitCodeHtb.put(bitCodeSb, bitCodeUsedNum);
			}
		}

		return bitCodeHtb;
	}

	/**
	 * 将<位编码字符，最多使用次数>的哈希表保存到算法配置文件中
	 * 
	 * @param newBitCodeHtb：
	 */
	public void setBitCodeHtb(Hashtable<String, Integer> newBitCodeHtb) {
		int oldLen = bitCodeHtb.size();
		int newLen = newBitCodeHtb.size();
		boolean isUpdated = false;
		int rule0UsedNum = 0;
		if (oldLen != newLen) {
			isUpdated = true;
		} else {
			boolean isEqual = true;
			Set<String> bitCodes = bitCodeHtb.keySet();
			for (Iterator<String> bitCode = bitCodes.iterator(); bitCode.hasNext();) {
				Integer bitCodeUsedNum = newBitCodeHtb.get(bitCode.next());
				Integer newbitCodeUsedNum = newBitCodeHtb.get(bitCode.next());
				if (bitCodeUsedNum == null) {
					isEqual = false;
					break;
				} else {

					if (bitCodeUsedNum.compareTo(newbitCodeUsedNum) != 0) {
						isEqual = false;
						break;
					}
				}
			}

			if (!isEqual) {
				isUpdated = true;
			}
		}
		if (isUpdated) {
			bitCodeHtb.clear();
			Set<String> newBitCodes = newBitCodeHtb.keySet();
			String newBitCodeInCfg = "";
			int k = 0;
			for (Iterator<String> newBitCode = newBitCodes.iterator(); newBitCode.hasNext();) {
				String bitCodeStr = newBitCode.next().trim();
				Integer bitCodeUsedNum = newBitCodeHtb.get(bitCodeStr);
				rule0UsedNum = rule0UsedNum + bitCodeUsedNum;
				if (k == 0) {
					newBitCodeInCfg = newBitCodeInCfg + "(" + bitCodeStr + "," + bitCodeUsedNum + ")";
				} else {
					newBitCodeInCfg = newBitCodeInCfg + ",(" + bitCodeStr + "," + bitCodeUsedNum + ")";
				}
				k++;
				bitCodeHtb.put(bitCodeStr, bitCodeUsedNum);
			}
			bitCodeHtb.put("0", rule0UsedNum);
			newBitCodeInCfg = newBitCodeInCfg + "," + "(" + "0," + rule0UsedNum + ")";
			propFileUtil.saveParameter("bitCodeStrs", newBitCodeInCfg);
			propFileUtil.saveParameter("chromLen", String.valueOf(rule0UsedNum));
		}
	}

	// 按一个参数一行输入GA的参数
	public List<List<DataCell>> ouPara(String runID, String startTime, String endTime, String host, String caseName,
			String algorithm) {
		List<List<DataCell>> paraRows = new ArrayList<List<DataCell>>();
		// 设置host行
		List<DataCell> hostRow = new ArrayList<DataCell>();
		DataCell hostDataCell = new DataCell();
		hostDataCell.setName("host");
		hostDataCell.setValue(host);
		hostRow.add(hostDataCell);
		paraRows.add(hostRow);
		// 设置caseName行
		List<DataCell> caseNameRow = new ArrayList<DataCell>();
		DataCell caseNameDataCell = new DataCell();
		caseNameDataCell.setName("caseName");
		caseNameDataCell.setValue(caseName);
		caseNameRow.add(caseNameDataCell);
		paraRows.add(caseNameRow);
		// 设置runID行
		List<DataCell> runIDRow = new ArrayList<DataCell>();
		DataCell runIDDataCell = new DataCell();
		runIDDataCell.setName("runID");
		runIDDataCell.setValue(runID);
		runIDRow.add(runIDDataCell);
		paraRows.add(runIDRow);
		// 设置开始时间行
		List<DataCell> startTimeRow = new ArrayList<DataCell>();
		DataCell startTimeDataCell = new DataCell();
		startTimeDataCell.setName("startTime");
		startTimeDataCell.setValue(startTime);
		startTimeRow.add(startTimeDataCell);
		paraRows.add(startTimeRow);
		// 设置结束时间行
		List<DataCell> endTimeRow = new ArrayList<DataCell>();
		DataCell endTimeDataCell = new DataCell();
		endTimeDataCell.setName("endTime");
		endTimeDataCell.setValue(endTime);
		endTimeRow.add(endTimeDataCell);
		paraRows.add(endTimeRow);
		// 设置编码信息行
		List<DataCell> bitCodeStrsRow = new ArrayList<DataCell>();
		DataCell bitCodeStrsDataCell = new DataCell();
		bitCodeStrsDataCell.setName("bitCodeStrs");
		bitCodeStrsDataCell.setValue(propFileUtil.getParameterValue("bitCodeStrs"));
		bitCodeStrsRow.add(bitCodeStrsDataCell);
		paraRows.add(bitCodeStrsRow);
		// 种群大小
		List<DataCell> popuSizeRow = new ArrayList<DataCell>();
		DataCell popuSizeDataCell = new DataCell();
		popuSizeDataCell.setName("popuSize");
		popuSizeDataCell.setValue(String.valueOf(getPopuSize()));
		popuSizeRow.add(popuSizeDataCell);
		paraRows.add(popuSizeRow);
		// 迭代次数
		List<DataCell> maxIterNumRow = new ArrayList<DataCell>();
		DataCell maxIterNumDataCell = new DataCell();
		maxIterNumDataCell.setName("maxIterNum");
		maxIterNumDataCell.setValue(String.valueOf(getMaxIterNum()));
		maxIterNumRow.add(maxIterNumDataCell);
		paraRows.add(maxIterNumRow);
		// 停机条件（不发生变化代数）
		List<DataCell> noChgGenNumRow = new ArrayList<DataCell>();
		DataCell noChgGenNumDataCell = new DataCell();
		noChgGenNumDataCell.setName("noChgGenNum");
		noChgGenNumDataCell.setValue(String.valueOf(getNoChgGenNum()));
		noChgGenNumRow.add(noChgGenNumDataCell);
		paraRows.add(noChgGenNumRow);
		// 变异概率
		List<DataCell> mutateProbRow = new ArrayList<DataCell>();
		DataCell mutateProbDataCell = new DataCell();
		mutateProbDataCell.setName("mutateProb");
		mutateProbDataCell.setValue(String.valueOf(getMutateProb()));
		mutateProbRow.add(mutateProbDataCell);
		paraRows.add(mutateProbRow);
		// 交叉概率
		List<DataCell> crossProbRow = new ArrayList<DataCell>();
		DataCell crossProbDataCell = new DataCell();
		crossProbDataCell.setName("crossProb");
		crossProbDataCell.setValue(String.valueOf(getCrossProb()));
		crossProbRow.add(crossProbDataCell);
		paraRows.add(crossProbRow);
		// 设置caseName行
		List<DataCell> algorithmRow = new ArrayList<DataCell>();
		DataCell algorithmDataCell = new DataCell();
		algorithmDataCell.setName("algorithm");
		algorithmDataCell.setValue(algorithm);
		algorithmRow.add(algorithmDataCell);
		paraRows.add(algorithmRow);

		return paraRows;
	}

	public boolean isNeeOutPara() {
		neeOutPara = Boolean.parseBoolean(propFileUtil.getParameterValue("neeOutPara").trim());
		return neeOutPara;
	}

	public void setNeeOutPara(boolean neeOutPara) {
		if (this.neeOutPara != neeOutPara) {
			this.neeOutPara = neeOutPara;
			propFileUtil.saveParameter("neeOutPara", String.valueOf(neeOutPara));
		}
	}

	public boolean isNeedOutPopulation() {
		needOutPopulation = Boolean.parseBoolean(propFileUtil.getParameterValue("needOutPopulation").trim());
		return needOutPopulation;
	}

	public void setNeedOutPopulation(boolean needOutPopulation) {
		if (this.needOutPopulation != needOutPopulation) {
			this.needOutPopulation = needOutPopulation;
			propFileUtil.saveParameter("needOutPopulation", String.valueOf(needOutPopulation));
		}
	}

	public boolean isNeedSurModel() {
		needSurModel = Boolean.parseBoolean(propFileUtil.getParameterValue("needSurModel").trim());
		return needSurModel;
	}

	public void setNeedSurModel(boolean needSurModel) {
		if (this.needSurModel != needSurModel) {
			this.needSurModel = needSurModel;
			propFileUtil.saveParameter("needSurModel", String.valueOf(needSurModel));
		}
	}

	public int getSampleNum() {
		sampleNum = Integer.parseInt(propFileUtil.getParameterValue("sampleNum"));
		return sampleNum;
	}

	public void setSampleNum(int sampleNum) {
		if (this.sampleNum != sampleNum) {
			this.sampleNum = sampleNum;
			propFileUtil.saveParameter("sampleNum", String.valueOf(sampleNum));
		}
	}

	public int getPredictNum() {
		predictNum = Integer.parseInt(propFileUtil.getParameterValue("predictNum"));
		return predictNum;
	}

	public void setPredictNum(int predictNum) {
		if(this.predictNum!=predictNum){
			this.predictNum=predictNum;
			propFileUtil.saveParameter("predictNum", String.valueOf(predictNum));
		}
	}

	public PropFileUtil getPropFileUtil() {
		return propFileUtil;
	}

	public void setPropFileUtil(PropFileUtil propFileUtil) {
		this.propFileUtil = propFileUtil;
	}

	public int getChromLen() {
		if (chromLen == 0) {
			chromLen = Integer.parseInt(propFileUtil.getParameterValue("chromLen").trim());
		}
		return chromLen;
	}

	public float getCrossProb() {
		if (Float.compare(crossProb, 0) == 0) {
			crossProb = Float.parseFloat(propFileUtil.getParameterValue("crossProb").trim());
		}
		return crossProb;
	}

	public void setCrossProb(float crosProb) {
		if (Float.compare(this.crossProb, crosProb) != 0) {
			this.crossProb = crosProb;
			propFileUtil.saveParameter("crossProb", String.valueOf(crosProb).trim());
		}
	}

	public float getMutateProb() {
		if (Float.compare(mutateProb, 0) == 0) {
			mutateProb = Float.parseFloat(propFileUtil.getParameterValue("mutateProb").trim());
		}
		return mutateProb;
	}

	public void setMutateProb(float mutateProb) {
		if (Float.compare(this.mutateProb, mutateProb) != 0) {
			this.mutateProb = mutateProb;
			propFileUtil.saveParameter("mutateProb", String.valueOf(mutateProb).trim());
		}

	}

	public int getMaxIterNum() {
		if (maxIterNum == 0) {
			maxIterNum = Integer.parseInt(propFileUtil.getParameterValue("maxIterNum").trim());
		}
		return maxIterNum;
	}

	public void setMaxIterNum(int maxIterNum) {
		if (this.maxIterNum != maxIterNum) {
			this.maxIterNum = maxIterNum;
			propFileUtil.saveParameter("maxIterNum", String.valueOf(maxIterNum).trim());
		}
	}

	public int getPopuSize() {
		if (popuSize == 0) {
			popuSize = Integer.parseInt(propFileUtil.getParameterValue("popuSize").trim());
		}
		return popuSize;
	}

	public void setPopuSize(int popuSize) {
		if (this.popuSize != popuSize) {
			this.popuSize = popuSize;
			propFileUtil.saveParameter("popuSize", String.valueOf(popuSize).trim());
		}
	}

	public int getNoChgGenNum() {
		if (noChgGenNum == 0) {
			noChgGenNum = Integer.parseInt(propFileUtil.getParameterValue("noChgGenNum").trim());
		}
		return noChgGenNum;
	}

	public void setNoChgGenNum(int noChgGenNum) {
		if (this.noChgGenNum != noChgGenNum) {
			this.noChgGenNum = noChgGenNum;
			propFileUtil.saveParameter("noChgGenNum", String.valueOf(noChgGenNum).trim());
		}
	}

}
